Conversation
|
Has commits from multiple different PRs |
📝 WalkthroughWalkthroughThis PR refactors and expands the filter system to support completed and deleted task filtering, introduces task dependency management with an interactive picker, implements system language following capability with proper localization configuration, and adds trust field support for task server configuration. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
lib/app/modules/home/views/tasks_builder.dart (1)
184-206:⚠️ Potential issue | 🟠 MajorPreserve the original status in the undo flow.
Line 184 now routes waiting tasks through the same swipe path as pending tasks, but
saveChanges()still restores'pending'unconditionally. Undoing a swipe on a task whose real status waswaitingwill bring it back with the wrong status.Possible fix
- void setStatus(BuildContext context, String newValue, String id) { + void setStatus( + BuildContext context, + String newValue, + String id, + String originalStatus, + ) { var storageWidget = Get.find<HomeController>(); Modify modify = Modify( getTask: storageWidget.getTask, mergeTask: storageWidget.mergeTask, uuid: id, ); modify.set('status', newValue); - saveChanges(context, modify, id, newValue); + saveChanges(context, modify, id, originalStatus); } - void saveChanges( - BuildContext context, Modify modify, String id, String newValue) async { + void saveChanges( + BuildContext context, Modify modify, String id, String originalStatus) async { ... onPressed: () { - undoChanges(context, id, 'pending'); + undoChanges(context, id, originalStatus); },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/app/modules/home/views/tasks_builder.dart` around lines 184 - 206, Capture the task's original status before you call setStatus in the SlidableAction onPressed and pass that original value into the undo/save flow instead of hardcoding 'pending'; e.g., read task.status (or task.state) into a local originalStatus, call setStatus(...), then ensure saveChanges()/undo restores originalStatus (not the literal 'pending') so waiting tasks are returned to 'waiting' when undone. Use the existing symbols setStatus, saveChanges, and task.status/task.uuid to locate and update the logic.lib/app/utils/taskfunctions/query.dart (1)
38-45:⚠️ Potential issue | 🟠 MajorHandle the upgrade path for legacy filter defaults.
These getters only change first-run initialization. Users who already have
pendingFilter/waitingFilterfiles created with the oldtruedefaults will keep those values, soHomeController._refreshTasks()never reaches the new "hide waiting tasks by default" branch until they manually reset filters. This needs a one-time migration or an explicit "unset vs user-chosen" state.Also applies to: 53-60
lib/app/v3/champion/models/task_for_replica.dart (1)
122-138:⚠️ Potential issue | 🟠 Major
operator==andhashCodedo not includedependsandprojectfields.The
dependsfield (and alsoproject) are excluded from equality comparison and hash computation. This violates the Dart contract that objects that are equal must have the same hash code, and could cause subtle bugs when usingTaskForReplicainSet,Map, or withList.contains().Proposed fix
`@override` bool operator ==(Object other) { if (identical(this, other)) return true; return other is TaskForReplica && other.modified == modified && other.due == due && other.start == start && other.wait == wait && other.status == status && other.description == description && _listEquals(other.tags, tags) && other.uuid == uuid && - other.priority == priority; + other.priority == priority && + other.project == project && + _listEquals(other.depends, depends); } `@override` - int get hashCode => Object.hash(modified, due, status, description, uuid, - priority, tags == null ? 0 : tags.hashCode, start, wait); + int get hashCode => Object.hash( + modified, + due, + status, + description, + uuid, + priority, + tags == null ? 0 : tags.hashCode, + start, + wait, + project, + depends == null ? 0 : depends.hashCode, + );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/app/v3/champion/models/task_for_replica.dart` around lines 122 - 138, The equality and hash computation for TaskForReplica omit the depends and project fields, breaking equality/hashCode consistency; update operator== (in the TaskForReplica class) to compare depends (using the same list comparison helper _listEquals if depends is a list) and project alongside the existing fields, and update int get hashCode to include depends and project (include a null-safe hash for depends similar to tags and incorporate project into Object.hash) so equal objects produce identical hashCodes.
🧹 Nitpick comments (7)
test/models/filters_test.dart (1)
71-119: Add assertions for the new filter states.This update wires
completedFilteranddeletedFilterinto the fixture, but the suite still never checks their initial values or toggle callbacks. A couple of focused tests here would lock down the expandedFiltersAPI and make regressions in this PR's filter behavior harder to reintroduce.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/models/filters_test.dart` around lines 71 - 119, Add tests asserting the initial values and toggle behavior for the newly wired completedFilter and deletedFilter: check filters.completedFilter and filters.deletedFilter initial states (e.g., expect(..., isFalse/isTrue as appropriate), call filters.toggleCompletedFilter() and assert the completedFilter changed, then call it again and assert it reverted; do the same for filters.toggleDeletedFilter(); reference the Filters instance and its properties completedFilter, deletedFilter and methods toggleCompletedFilter, toggleDeletedFilter to locate where to add the assertions in the existing tests.lib/main.dart (1)
5-5: Remove development comments before merging.Comments like
// ADD THISand// ADD THESE 3 PROPERTIESappear to be development reminders and should be removed for cleaner production code.Also applies to: 70-71
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/main.dart` at line 5, Remove development reminder comments such as "// ADD THIS" in the import line for flutter_localizations (import 'package:flutter_localizations/flutter_localizations.dart') and any other inline notes like "// ADD THESE 3 PROPERTIES" found around lines ~70-71; open lib/main.dart, locate the import and the commented reminders and delete those comment fragments so only production-ready code and necessary comments remain, then run a quick build/lint to ensure no leftover TODO/dev comments remain.lib/app/utils/language/supported_language.dart (2)
77-82:toLocale()returns English when called onSupportedLanguage.system, which may not match user expectations.When
this == SupportedLanguage.system, this method returnsLocale('en')unconditionally rather than resolving the actual system language. While the current call site insettings_controller.dartcorrectly usesgetSystemLanguage().toLocale(), callingSupportedLanguage.system.toLocale()directly would yield incorrect results.Consider either:
- Throwing an
UnsupportedErrorfor thesystemcase to enforce proper usage, or- Delegating to
getSystemLanguage().toLocale()for consistency.Option 1: Enforce proper usage by throwing
Locale toLocale() { - if (this == SupportedLanguage.system || languageCode.isEmpty) { - return const Locale('en'); + if (this == SupportedLanguage.system) { + throw UnsupportedError( + 'Cannot convert system to Locale directly; use getSystemLanguage().toLocale()', + ); + } + if (languageCode.isEmpty) { + return const Locale('en'); } return Locale(languageCode); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/app/utils/language/supported_language.dart` around lines 77 - 82, The toLocale() method on SupportedLanguage currently returns Locale('en') for SupportedLanguage.system; change it to either (a) throw an UnsupportedError when this == SupportedLanguage.system (e.g., in toLocale() throw UnsupportedError('toLocale() must not be called on SupportedLanguage.system; use getSystemLanguage() instead')) to enforce correct usage, or (b) resolve the actual system language by delegating to getSystemLanguage().toLocale() when this == SupportedLanguage.system so SupportedLanguage.system.toLocale() returns the real system locale; update the implementation of SupportedLanguage.toLocale() accordingly and keep the rest of the codepaths (e.g., callers that already call getSystemLanguage().toLocale()) unchanged.
36-38: Unreachable default case.All
SupportedLanguageenum values are explicitly handled in the switch, making thedefaultbranch dead code. Removing it enables compile-time exhaustiveness checks if a new language is added later.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/app/utils/language/supported_language.dart` around lines 36 - 38, The switch over the SupportedLanguage enum currently includes a default branch which is unreachable; remove the default case in the switch so the compiler can enforce exhaustiveness when new SupportedLanguage values are added, and ensure every SupportedLanguage case in the switch (the branches returning the language string) remains present so the function still returns a value for all enum members.lib/app/modules/home/views/filter_drawer_home_page.dart (1)
196-200: Duplicate dividers.There are two consecutive
Dividerwidgets (lines 196 and 198-200), which creates unnecessary spacing.Proposed fix
), - const Divider(color: Color.fromARGB(0, 48, 46, 46)), - const Divider( color: Color.fromARGB(0, 48, 46, 46), ),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/app/modules/home/views/filter_drawer_home_page.dart` around lines 196 - 200, Two consecutive Divider widgets with identical color (Color.fromARGB(0, 48, 46, 46)) are duplicated in the widget tree; remove the redundant Divider so only a single Divider remains (inside the build of the filter drawer widget in filter_drawer_home_page.dart) to eliminate extra spacing and keep layout consistent, then run formatter/analysis to ensure no trailing commas or style issues.lib/app/modules/home/controllers/home_controller.dart (2)
750-751: Remove leftover development comment.The comment "REPLACE this entire Filters() instantiation:" appears to be a leftover from development that should be removed before merging.
- // REPLACE this entire Filters() instantiation: var filters = Filters(🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/app/modules/home/controllers/home_controller.dart` around lines 750 - 751, Remove the leftover development comment "REPLACE this entire Filters() instantiation:" from the home controller; locate the Filters() instantiation in HomeController (or the Filters constructor call near the UI/filter setup) and delete that stray comment so only the actual Filters() code and surrounding logic remain, ensuring no other functional code is altered.
600-635: Consider cancelling the auto-dismiss timer on manual dismissal.The 5-second
Future.delayedtimer continues running even after the user manually dismisses the banner. WhilehideCurrentMaterialBanner()is idempotent, if another banner is shown in the meantime, the timer could inadvertently hide it.Optional: Use a cancellable timer
Timer? _bannerDismissTimer; void showTaskServerNotConfiguredBanner(BuildContext context) { if (taskServerBannerShown.value) return; taskServerBannerShown.value = true; final messenger = ScaffoldMessenger.of(context); messenger.clearMaterialBanners(); void dismissBanner() { _bannerDismissTimer?.cancel(); messenger.hideCurrentMaterialBanner(); taskServerBannerShown.value = false; } messenger.showMaterialBanner( MaterialBanner( content: Text(sentences.homePageTaskWarriorNotConfigured), actions: [ TextButton( onPressed: () { dismissBanner(); Get.toNamed(Routes.MANAGE_TASK_SERVER); }, child: Text(sentences.homePageSetup), ), TextButton( onPressed: dismissBanner, child: const Text('Dismiss'), ), ], ), ); _bannerDismissTimer = Timer(const Duration(seconds: 5), dismissBanner); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/app/modules/home/controllers/home_controller.dart` around lines 600 - 635, The Future.delayed in showTaskServerNotConfiguredBanner keeps running after manual dismiss and can hide a subsequently shown banner; change this to use a cancellable Timer (e.g., a top-level or class field Timer? _bannerDismissTimer), create a single dismissBanner() helper that calls _bannerDismissTimer?.cancel(), messenger.hideCurrentMaterialBanner(), and sets taskServerBannerShown.value = false, call dismissBanner() from both action handlers, and replace Future.delayed(...) with _bannerDismissTimer = Timer(const Duration(seconds: 5), dismissBanner); ensure you reference showTaskServerNotConfiguredBanner, taskServerBannerShown, messenger.hideCurrentMaterialBanner, and replace Future.delayed with Timer usage.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@lib/app/modules/home/controllers/home_controller.dart`:
- Around line 259-298: The _refreshTasks method's filter order is wrong:
waitingFilter is applied after hideBlocked and replaces queriedTasks, causing
hideBlocked to be ignored for waiting views; fix by capturing DateTime.now()
once at method start (assign to currentTime), then move the waitingFilter branch
into the main if-else chain alongside
deletedFilter/completedFilter/pendingFilter so it produces queriedTasks from
storage.data.pendingData() like the others, or if waiting should ignore
hideBlocked explicitly apply hideBlocked only for the non-waiting branches; also
remove or update the misleading "Rest of the method stays the same..." comment
so it reflects the new flow (references: _refreshTasks, waitingFilter,
hideBlocked, queriedTasks, storage.data.pendingData(),
storage.data.completedData()).
In `@lib/app/modules/home/views/filter_drawer_home_page.dart`:
- Around line 100-112: Replace the hardcoded English labels with localized
sentences from SentenceManager: where the ternary uses 'Deleted' (the expression
referencing filters.deletedFilter / filters.completedFilter) switch it to
SentenceManager(currentLanguage:
homeController.selectedLanguage.value).sentences.filterDrawerDeleted; likewise
replace 'Show Deleted' and 'Hide Blocked Tasks' with
SentenceManager(...).sentences.filterDrawerShowDeleted and
SentenceManager(...).sentences.filterDrawerHideBlockedTasks respectively
(consistent with how filterDrawerCompleted/filterDrawerPending are used) and add
those keys to SentenceManager if they do not already exist.
- Around line 151-167: The UI is missing a "Show Waiting" toggle: add a row
identical to the existing "Show Deleted" entry but using the localized string
key filterDrawerShowWaiting for the label and binding the Switch to the waiting
filter state and toggle methods (use filters.waitingFilter for value and call
filters.toggleWaitingFilter() in onChanged). Match the existing Text style
(FontFamily.poppins, TaskWarriorFonts.fontSizeMedium, tColors.primaryTextColor)
and place the new toggle alongside the other filter switches in the same
container so users can control waiting-task visibility.
In
`@lib/app/modules/manageTaskServer/controllers/manage_task_server_controller.dart`:
- Around line 56-57: The fixture loader setConfigurationFromFixtureForDebugging
currently parses Taskrc and only assigns trust (taskrc.trust), leaving
controller fields server and credentials stale; update the same method to also
refresh server and credentials from the parsed Taskrc (e.g., assign server =
taskrc.server and credentials = taskrc.credentials or map equivalent fields) so
controller state stays in sync with the fixture; locate the assignments in
setConfigurationFromFixtureForDebugging and ensure all relevant controller
properties (trust, server, credentials) are updated from Taskrc.
In
`@lib/app/modules/settings/views/settings_page_select_the_language_trailing.dart`:
- Around line 47-48: The literal 'Follow System Language' returned for
SupportedLanguage.system should be replaced with the app's localized string;
update the switch/case that maps SupportedLanguage to a label (the code
returning that literal) to call the project's localization accessor (e.g.
AppLocalizations.of(context).followSystemLanguage or
context.l10n.followSystemLanguage) instead of the hard-coded English text,
ensuring you obtain a BuildContext where this mapping function is called or pass
context into it.
In `@lib/app/modules/taskc_details/controllers/taskc_details_controller.dart`:
- Around line 507-553: The dependency picker mutates depends and sets hasChanges
but those changes are never persisted; update the save paths so the edited
depends list is written back: when calling saveEditedTaskInDB(...) ensure the
TaskForC instance passed includes the updated depends, and when building the
TaskForReplica in saveTask() set its depends field from the controller's depends
list (or propagate depends into whatever object is saved); modify the
saveEditedTaskInDB callsite and the TaskForReplica construction to copy the
current depends list so selected dependencies are persisted.
- Around line 524-533: The code is force-unwrapping nullable TaskForC.uuid
(t.uuid!) inside the CheckboxListTile which can throw; update the list building
to skip tasks with null UUIDs (e.g., add .where((t) => t.uuid != null) to the
chain) or otherwise use a safe non-null key (e.g., use a stable fallback like
t.hashCode or t.id if available) and replace t.uuid! with the safe value; ensure
references to depends.contains(...) and depends.add(...) use the same non-null
identifier so no forced unwrapping occurs (check symbols: allTasks, initialTask,
depends, t.uuid, CheckboxListTile).
In `@lib/app/utils/app_settings/selected_language.dart`:
- Around line 26-28: The clearSelectedLanguage method is missing its closing
brace and the class lacks a blank line before the final closing brace; add the
missing closing brace to terminate the static Future clearSelectedLanguage()
async { ... } method (which uses _preferences?.remove('_selectedLanguage')),
ensure the method body is properly closed, and insert a single blank line before
the class's closing brace to match file formatting.
In `@lib/main.dart`:
- Around line 72-79: The supportedLocales list in main.dart is missing the
German and Urdu entries defined in SupportedLanguage, causing locale fallback
for those selections; update the supportedLocales constant (the list referenced
by supportedLocales) to include Locale('de') and Locale('ur') so it matches the
SupportedLanguage enum in lib/app/utils/language/supported_language.dart and
ensure any related locale resolution logic uses those entries.
---
Outside diff comments:
In `@lib/app/modules/home/views/tasks_builder.dart`:
- Around line 184-206: Capture the task's original status before you call
setStatus in the SlidableAction onPressed and pass that original value into the
undo/save flow instead of hardcoding 'pending'; e.g., read task.status (or
task.state) into a local originalStatus, call setStatus(...), then ensure
saveChanges()/undo restores originalStatus (not the literal 'pending') so
waiting tasks are returned to 'waiting' when undone. Use the existing symbols
setStatus, saveChanges, and task.status/task.uuid to locate and update the
logic.
In `@lib/app/v3/champion/models/task_for_replica.dart`:
- Around line 122-138: The equality and hash computation for TaskForReplica omit
the depends and project fields, breaking equality/hashCode consistency; update
operator== (in the TaskForReplica class) to compare depends (using the same list
comparison helper _listEquals if depends is a list) and project alongside the
existing fields, and update int get hashCode to include depends and project
(include a null-safe hash for depends similar to tags and incorporate project
into Object.hash) so equal objects produce identical hashCodes.
---
Nitpick comments:
In `@lib/app/modules/home/controllers/home_controller.dart`:
- Around line 750-751: Remove the leftover development comment "REPLACE this
entire Filters() instantiation:" from the home controller; locate the Filters()
instantiation in HomeController (or the Filters constructor call near the
UI/filter setup) and delete that stray comment so only the actual Filters() code
and surrounding logic remain, ensuring no other functional code is altered.
- Around line 600-635: The Future.delayed in showTaskServerNotConfiguredBanner
keeps running after manual dismiss and can hide a subsequently shown banner;
change this to use a cancellable Timer (e.g., a top-level or class field Timer?
_bannerDismissTimer), create a single dismissBanner() helper that calls
_bannerDismissTimer?.cancel(), messenger.hideCurrentMaterialBanner(), and sets
taskServerBannerShown.value = false, call dismissBanner() from both action
handlers, and replace Future.delayed(...) with _bannerDismissTimer = Timer(const
Duration(seconds: 5), dismissBanner); ensure you reference
showTaskServerNotConfiguredBanner, taskServerBannerShown,
messenger.hideCurrentMaterialBanner, and replace Future.delayed with Timer
usage.
In `@lib/app/modules/home/views/filter_drawer_home_page.dart`:
- Around line 196-200: Two consecutive Divider widgets with identical color
(Color.fromARGB(0, 48, 46, 46)) are duplicated in the widget tree; remove the
redundant Divider so only a single Divider remains (inside the build of the
filter drawer widget in filter_drawer_home_page.dart) to eliminate extra spacing
and keep layout consistent, then run formatter/analysis to ensure no trailing
commas or style issues.
In `@lib/app/utils/language/supported_language.dart`:
- Around line 77-82: The toLocale() method on SupportedLanguage currently
returns Locale('en') for SupportedLanguage.system; change it to either (a) throw
an UnsupportedError when this == SupportedLanguage.system (e.g., in toLocale()
throw UnsupportedError('toLocale() must not be called on
SupportedLanguage.system; use getSystemLanguage() instead')) to enforce correct
usage, or (b) resolve the actual system language by delegating to
getSystemLanguage().toLocale() when this == SupportedLanguage.system so
SupportedLanguage.system.toLocale() returns the real system locale; update the
implementation of SupportedLanguage.toLocale() accordingly and keep the rest of
the codepaths (e.g., callers that already call getSystemLanguage().toLocale())
unchanged.
- Around line 36-38: The switch over the SupportedLanguage enum currently
includes a default branch which is unreachable; remove the default case in the
switch so the compiler can enforce exhaustiveness when new SupportedLanguage
values are added, and ensure every SupportedLanguage case in the switch (the
branches returning the language string) remains present so the function still
returns a value for all enum members.
In `@lib/main.dart`:
- Line 5: Remove development reminder comments such as "// ADD THIS" in the
import line for flutter_localizations (import
'package:flutter_localizations/flutter_localizations.dart') and any other inline
notes like "// ADD THESE 3 PROPERTIES" found around lines ~70-71; open
lib/main.dart, locate the import and the commented reminders and delete those
comment fragments so only production-ready code and necessary comments remain,
then run a quick build/lint to ensure no leftover TODO/dev comments remain.
In `@test/models/filters_test.dart`:
- Around line 71-119: Add tests asserting the initial values and toggle behavior
for the newly wired completedFilter and deletedFilter: check
filters.completedFilter and filters.deletedFilter initial states (e.g.,
expect(..., isFalse/isTrue as appropriate), call filters.toggleCompletedFilter()
and assert the completedFilter changed, then call it again and assert it
reverted; do the same for filters.toggleDeletedFilter(); reference the Filters
instance and its properties completedFilter, deletedFilter and methods
toggleCompletedFilter, toggleDeletedFilter to locate where to add the assertions
in the existing tests.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 43f67d64-f25a-4800-8ae4-a944aac807be
📒 Files selected for processing (21)
lib/app/models/filters.dartlib/app/models/tag_filters.dartlib/app/modules/home/controllers/home_controller.dartlib/app/modules/home/views/filter_drawer_home_page.dartlib/app/modules/home/views/tasks_builder.dartlib/app/modules/manageTaskServer/controllers/manage_task_server_controller.dartlib/app/modules/settings/controllers/settings_controller.dartlib/app/modules/settings/views/settings_page_select_the_language_trailing.dartlib/app/modules/taskc_details/controllers/taskc_details_controller.dartlib/app/modules/taskc_details/views/taskc_details_view.dartlib/app/services/tag_filter.dartlib/app/utils/add_task_dialogue/date_picker_input.dartlib/app/utils/app_settings/app_settings.dartlib/app/utils/app_settings/selected_language.dartlib/app/utils/language/supported_language.dartlib/app/utils/taskfunctions/query.dartlib/app/utils/taskserver/taskrc.dartlib/app/v3/champion/models/task_for_replica.dartlib/main.dartpubspec.yamltest/models/filters_test.dart
| void _refreshTasks() { | ||
| if (pendingFilter.value) { | ||
|
|
||
| if (deletedFilter.value) { | ||
| queriedTasks.value = storage.data | ||
| .completedData() | ||
| .where((task) => task.status == 'deleted') | ||
| .toList(); | ||
| } else if (completedFilter.value) { | ||
| queriedTasks.value = storage.data | ||
| .completedData() | ||
| .where((task) => task.status == 'completed') | ||
| .toList(); | ||
| } else if (pendingFilter.value) { | ||
| queriedTasks.value = storage.data | ||
| .pendingData() | ||
| .where((task) => task.status == 'pending') | ||
| .toList(); | ||
| } else { | ||
| queriedTasks.value = storage.data.completedData(); | ||
| var currentTime = DateTime.now(); | ||
| queriedTasks.value = storage.data.pendingData().where((task) => | ||
| task.status != 'waiting' && | ||
| !(task.wait != null && task.wait!.isAfter(currentTime)) | ||
| ).toList(); | ||
| } | ||
|
|
||
| if (waitingFilter.value) { | ||
| var currentTime = DateTime.now(); | ||
| if (hideBlocked.value) { | ||
| queriedTasks.value = queriedTasks | ||
| .where((task) => task.wait != null && task.wait!.isAfter(currentTime)) | ||
| .where((task) => task.depends == null || task.depends!.isEmpty) | ||
| .toList(); | ||
| } | ||
|
|
||
|
|
||
| // Rest of the method stays the same... | ||
| if (waitingFilter.value) { | ||
| var currentTime = DateTime.now(); | ||
| queriedTasks.value = storage.data.pendingData().where((task) => | ||
| task.status == 'waiting' || | ||
| (task.wait != null && task.wait!.isAfter(currentTime)) | ||
| ).toList(); | ||
| } |
There was a problem hiding this comment.
Filter logic structure is confusing and potentially incorrect.
The waitingFilter check (lines 292-298) sits outside the main if-else chain and runs after hideBlocked filtering. This means when waitingFilter is enabled, it completely replaces queriedTasks with a fresh query, ignoring the hideBlocked filter that was just applied.
If this is intentional (waiting tasks should ignore blocked filtering), the code flow would be clearer with waitingFilter inside the main if-else chain. If unintentional, blocked tasks would incorrectly appear when viewing waiting tasks.
Additionally:
- Line 291's comment "Rest of the method stays the same..." is misleading since the waitingFilter code that follows is new logic.
DateTime.now()is called twice (lines 277 and 293); consider capturing it once at the method start.
Suggested refactor to clarify intent
void _refreshTasks() {
-
+ var currentTime = DateTime.now();
+
if (deletedFilter.value) {
queriedTasks.value = storage.data
.completedData()
.where((task) => task.status == 'deleted')
.toList();
} else if (completedFilter.value) {
queriedTasks.value = storage.data
.completedData()
.where((task) => task.status == 'completed')
.toList();
+ } else if (waitingFilter.value) {
+ queriedTasks.value = storage.data.pendingData().where((task) =>
+ task.status == 'waiting' ||
+ (task.wait != null && task.wait!.isAfter(currentTime))
+ ).toList();
} else if (pendingFilter.value) {
queriedTasks.value = storage.data
.pendingData()
.where((task) => task.status == 'pending')
.toList();
} else {
- var currentTime = DateTime.now();
queriedTasks.value = storage.data.pendingData().where((task) =>
task.status != 'waiting' &&
!(task.wait != null && task.wait!.isAfter(currentTime))
).toList();
}
if (hideBlocked.value) {
queriedTasks.value = queriedTasks
.where((task) => task.depends == null || task.depends!.isEmpty)
.toList();
}
-
- // Rest of the method stays the same...
- if (waitingFilter.value) {
- var currentTime = DateTime.now();
- queriedTasks.value = storage.data.pendingData().where((task) =>
- task.status == 'waiting' ||
- (task.wait != null && task.wait!.isAfter(currentTime))
- ).toList();
- }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/app/modules/home/controllers/home_controller.dart` around lines 259 -
298, The _refreshTasks method's filter order is wrong: waitingFilter is applied
after hideBlocked and replaces queriedTasks, causing hideBlocked to be ignored
for waiting views; fix by capturing DateTime.now() once at method start (assign
to currentTime), then move the waitingFilter branch into the main if-else chain
alongside deletedFilter/completedFilter/pendingFilter so it produces
queriedTasks from storage.data.pendingData() like the others, or if waiting
should ignore hideBlocked explicitly apply hideBlocked only for the non-waiting
branches; also remove or update the misleading "Rest of the method stays the
same..." comment so it reflects the new flow (references: _refreshTasks,
waitingFilter, hideBlocked, queriedTasks, storage.data.pendingData(),
storage.data.completedData()).
| text: filters.deletedFilter | ||
| ? 'Deleted' | ||
| : filters.completedFilter | ||
| ? SentenceManager( | ||
| currentLanguage: | ||
| homeController.selectedLanguage.value) | ||
| .sentences | ||
| .filterDrawerCompleted | ||
| : SentenceManager( | ||
| currentLanguage: | ||
| homeController.selectedLanguage.value) | ||
| .sentences | ||
| .filterDrawerPending, |
There was a problem hiding this comment.
Hardcoded English strings break internationalization.
Several UI strings are hardcoded in English instead of using SentenceManager:
- Line 101:
'Deleted' - Line 152:
'Show Deleted' - Line 181:
'Hide Blocked Tasks'
Other strings in this file correctly use SentenceManager for localization consistency.
Example fix pattern
- text: filters.deletedFilter
- ? 'Deleted'
+ text: filters.deletedFilter
+ ? SentenceManager(
+ currentLanguage:
+ homeController.selectedLanguage.value)
+ .sentences
+ .filterDrawerDeletedAlso applies to: 151-158, 180-187
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/app/modules/home/views/filter_drawer_home_page.dart` around lines 100 -
112, Replace the hardcoded English labels with localized sentences from
SentenceManager: where the ternary uses 'Deleted' (the expression referencing
filters.deletedFilter / filters.completedFilter) switch it to
SentenceManager(currentLanguage:
homeController.selectedLanguage.value).sentences.filterDrawerDeleted; likewise
replace 'Show Deleted' and 'Hide Blocked Tasks' with
SentenceManager(...).sentences.filterDrawerShowDeleted and
SentenceManager(...).sentences.filterDrawerHideBlockedTasks respectively
(consistent with how filterDrawerCompleted/filterDrawerPending are used) and add
those keys to SentenceManager if they do not already exist.
| Text( | ||
| !filters.waitingFilter | ||
| ? SentenceManager( | ||
| currentLanguage: homeController | ||
| .selectedLanguage.value) | ||
| .sentences | ||
| .filterDrawerShowWaiting | ||
| : SentenceManager( | ||
| currentLanguage: homeController | ||
| .selectedLanguage.value) | ||
| .sentences | ||
| .filterDrawerHideWaiting, | ||
| style: TextStyle( | ||
| fontFamily: FontFamily.poppins, | ||
| fontSize: TaskWarriorFonts.fontSizeMedium, | ||
| color: tColors.primaryTextColor, | ||
| )), | ||
| 'Show Deleted', | ||
| style: TextStyle( | ||
| fontFamily: FontFamily.poppins, | ||
| fontSize: TaskWarriorFonts.fontSizeMedium, | ||
| color: tColors.primaryTextColor, | ||
| ), | ||
| ), | ||
| Switch( | ||
| value: filters.waitingFilter, | ||
| onChanged: (_) => filters.toggleWaitingFilter(), | ||
| ) | ||
| value: filters.deletedFilter, | ||
| onChanged: (_) => filters.toggleDeletedFilter(), | ||
| ), | ||
| ], | ||
| ), | ||
| ), | ||
| ), | ||
| ), |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for waitingFilter toggle usage in the codebase
rg -n "waitingFilter|toggleWaitingFilter|Show.*Waiting" --type=dart -g '!test/**'Repository: CCExtractor/taskwarrior-flutter
Length of output: 3549
🏁 Script executed:
cat -n lib/app/modules/home/views/filter_drawer_home_page.dartRepository: CCExtractor/taskwarrior-flutter
Length of output: 26400
Add "Show Waiting" toggle to filter drawer — feature exists but is not accessible in the UI.
The waiting filter infrastructure exists in the codebase (controller, models, persistence), with language strings already defined (filterDrawerShowWaiting), but the UI toggle is absent from the filter drawer. Users have no way to control waiting task visibility through the filter interface, despite the feature being functional in the backend.
Add a "Show Waiting" switch alongside the other filter toggles to expose this functionality to users.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/app/modules/home/views/filter_drawer_home_page.dart` around lines 151 -
167, The UI is missing a "Show Waiting" toggle: add a row identical to the
existing "Show Deleted" entry but using the localized string key
filterDrawerShowWaiting for the label and binding the Switch to the waiting
filter state and toggle methods (use filters.waitingFilter for value and call
filters.toggleWaitingFilter() in onChanged). Match the existing Text style
(FontFamily.poppins, TaskWarriorFonts.fontSizeMedium, tColors.primaryTextColor)
and place the new toggle alongside the other filter switches in the same
container so users can control waiting-task visibility.
| var taskrc = Taskrc.fromString(contents); | ||
| server = taskrc.server; | ||
| credentials = taskrc.credentials; | ||
| trust = taskrc.trust; |
There was a problem hiding this comment.
Fixture load updates only trust, leaving controller state partially stale.
At Line 57, setConfigurationFromFixtureForDebugging() refreshes trust but not server/credentials from the same parsed Taskrc. That can desync in-memory state from the fixture file.
Proposed fix
var taskrc = Taskrc.fromString(contents);
+ server = taskrc.server;
+ credentials = taskrc.credentials;
trust = taskrc.trust;
+ configureCredentialString();🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@lib/app/modules/manageTaskServer/controllers/manage_task_server_controller.dart`
around lines 56 - 57, The fixture loader setConfigurationFromFixtureForDebugging
currently parses Taskrc and only assigns trust (taskrc.trust), leaving
controller fields server and credentials stale; update the same method to also
refresh server and credentials from the parsed Taskrc (e.g., assign server =
taskrc.server and credentials = taskrc.credentials or map equivalent fields) so
controller state stays in sync with the fixture; locate the assignments in
setConfigurationFromFixtureForDebugging and ensure all relevant controller
properties (trust, server, credentials) are updated from Taskrc.
| case SupportedLanguage.system: | ||
| return 'Follow System Language'; |
There was a problem hiding this comment.
Localize the new system-language label.
Follow System Language bypasses the app's translation layer, so this new option will stay in English even when the rest of Settings is localized.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@lib/app/modules/settings/views/settings_page_select_the_language_trailing.dart`
around lines 47 - 48, The literal 'Follow System Language' returned for
SupportedLanguage.system should be replaced with the app's localized string;
update the switch/case that maps SupportedLanguage to a label (the code
returning that literal) to call the project's localization accessor (e.g.
AppLocalizations.of(context).followSystemLanguage or
context.l10n.followSystemLanguage) instead of the hard-coded English text,
ensuring you obtain a BuildContext where this mapping function is called or pass
context into it.
| Future<void> showDependencyPicker() async { | ||
| // Get all pending tasks except current | ||
| final allTasks = await taskDatabase.fetchTasksFromDatabase(); | ||
| final BuildContext context = Get.context!; | ||
| TaskwarriorColorTheme tColors = | ||
| Theme.of(context).extension<TaskwarriorColorTheme>()!; | ||
|
|
||
| await Get.dialog( | ||
| AlertDialog( | ||
| backgroundColor: tColors.secondaryBackgroundColor, | ||
| title: Text('Select Dependencies', style: TextStyle(color: tColors.primaryTextColor)), | ||
| content: StatefulBuilder( | ||
| builder: (context, setState) { | ||
| return SizedBox( | ||
| width: double.maxFinite, | ||
| child: ListView( | ||
| shrinkWrap: true, | ||
| children: allTasks | ||
| .where((t) => t.uuid != initialTask.uuid && t.status == 'pending') | ||
| .map((t) => CheckboxListTile( | ||
| title: Text(t.description, style: TextStyle(color: tColors.primaryTextColor)), | ||
| value: depends.contains(t.uuid), | ||
| onChanged: (checked) { | ||
| setState(() { | ||
| if (checked == true) { | ||
| depends.add(t.uuid!); | ||
| } else { | ||
| depends.remove(t.uuid); | ||
| } | ||
| hasChanges.value = true; | ||
| }); | ||
| }, | ||
| )) | ||
| .toList(), | ||
| ), | ||
| ); | ||
| }, | ||
| ), | ||
| actions: [ | ||
| TextButton( | ||
| onPressed: () => Get.back(), | ||
| child: Text('Done', style: TextStyle(color: tColors.primaryTextColor)), | ||
| ), | ||
| ], | ||
| ), | ||
| ); | ||
| } |
There was a problem hiding this comment.
Dependency edits are never persisted.
This dialog mutates depends and flips hasChanges, but neither save path writes that list back out: saveEditedTaskInDB(...) is still called without depends for TaskForC, and the TaskForReplica built in saveTask() never sets depends. Users can select dependencies, tap save, and silently lose the change.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/app/modules/taskc_details/controllers/taskc_details_controller.dart`
around lines 507 - 553, The dependency picker mutates depends and sets
hasChanges but those changes are never persisted; update the save paths so the
edited depends list is written back: when calling saveEditedTaskInDB(...) ensure
the TaskForC instance passed includes the updated depends, and when building the
TaskForReplica in saveTask() set its depends field from the controller's depends
list (or propagate depends into whatever object is saved); modify the
saveEditedTaskInDB callsite and the TaskForReplica construction to copy the
current depends list so selected dependencies are persisted.
| children: allTasks | ||
| .where((t) => t.uuid != initialTask.uuid && t.status == 'pending') | ||
| .map((t) => CheckboxListTile( | ||
| title: Text(t.description, style: TextStyle(color: tColors.primaryTextColor)), | ||
| value: depends.contains(t.uuid), | ||
| onChanged: (checked) { | ||
| setState(() { | ||
| if (checked == true) { | ||
| depends.add(t.uuid!); | ||
| } else { |
There was a problem hiding this comment.
Don't force-unwrap nullable task UUIDs here.
TaskForC.uuid is nullable, so selecting a pending task without a UUID will throw at t.uuid!. Either filter those rows out before building the list or use a non-null fallback identifier.
Minimal guard
children: allTasks
- .where((t) => t.uuid != initialTask.uuid && t.status == 'pending')
+ .where((t) => t.uuid != null && t.uuid != initialTask.uuid && t.status == 'pending')📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| children: allTasks | |
| .where((t) => t.uuid != initialTask.uuid && t.status == 'pending') | |
| .map((t) => CheckboxListTile( | |
| title: Text(t.description, style: TextStyle(color: tColors.primaryTextColor)), | |
| value: depends.contains(t.uuid), | |
| onChanged: (checked) { | |
| setState(() { | |
| if (checked == true) { | |
| depends.add(t.uuid!); | |
| } else { | |
| children: allTasks | |
| .where((t) => t.uuid != null && t.uuid != initialTask.uuid && t.status == 'pending') | |
| .map((t) => CheckboxListTile( | |
| title: Text(t.description, style: TextStyle(color: tColors.primaryTextColor)), | |
| value: depends.contains(t.uuid), | |
| onChanged: (checked) { | |
| setState(() { | |
| if (checked == true) { | |
| depends.add(t.uuid!); | |
| } else { |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/app/modules/taskc_details/controllers/taskc_details_controller.dart`
around lines 524 - 533, The code is force-unwrapping nullable TaskForC.uuid
(t.uuid!) inside the CheckboxListTile which can throw; update the list building
to skip tasks with null UUIDs (e.g., add .where((t) => t.uuid != null) to the
chain) or otherwise use a safe non-null key (e.g., use a stable fallback like
t.hashCode or t.id if available) and replace t.uuid! with the safe value; ensure
references to depends.contains(...) and depends.add(...) use the same non-null
identifier so no forced unwrapping occurs (check symbols: allTasks, initialTask,
depends, t.uuid, CheckboxListTile).
| static Future clearSelectedLanguage() async { | ||
| await _preferences?.remove('_selectedLanguage'); | ||
| } |
There was a problem hiding this comment.
Missing closing brace/newline formatting.
The clearSelectedLanguage method is missing a closing brace for the method body, and there's no blank line before the class closing brace.
Proposed fix
static Future clearSelectedLanguage() async {
await _preferences?.remove('_selectedLanguage');
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| static Future clearSelectedLanguage() async { | |
| await _preferences?.remove('_selectedLanguage'); | |
| } | |
| static Future clearSelectedLanguage() async { | |
| await _preferences?.remove('_selectedLanguage'); | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/app/utils/app_settings/selected_language.dart` around lines 26 - 28, The
clearSelectedLanguage method is missing its closing brace and the class lacks a
blank line before the final closing brace; add the missing closing brace to
terminate the static Future clearSelectedLanguage() async { ... } method (which
uses _preferences?.remove('_selectedLanguage')), ensure the method body is
properly closed, and insert a single blank line before the class's closing brace
to match file formatting.
| supportedLocales: const [ | ||
| Locale('en'), | ||
| Locale('hi'), | ||
| Locale('mr'), | ||
| Locale('fr'), | ||
| Locale('es'), | ||
| Locale('bn'), | ||
| ], |
There was a problem hiding this comment.
Missing locales: de (German) and ur (Urdu) are defined in SupportedLanguage but not in supportedLocales.
The SupportedLanguage enum in lib/app/utils/language/supported_language.dart includes german ('de') and urdu ('ur'), but they're absent from supportedLocales. This mismatch will cause Flutter to fall back to the default locale when a user selects German or Urdu, potentially resulting in unexpected behavior.
Proposed fix
supportedLocales: const [
Locale('en'),
Locale('hi'),
Locale('mr'),
Locale('fr'),
Locale('es'),
Locale('bn'),
+ Locale('de'),
+ Locale('ur'),
],🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/main.dart` around lines 72 - 79, The supportedLocales list in main.dart
is missing the German and Urdu entries defined in SupportedLanguage, causing
locale fallback for those selections; update the supportedLocales constant (the
list referenced by supportedLocales) to include Locale('de') and Locale('ur') so
it matches the SupportedLanguage enum in
lib/app/utils/language/supported_language.dart and ensure any related locale
resolution logic uses those entries.
Description
Waiting tasks (tasks with a future
waitdate orstatus == 'waiting')are now hidden from the default Pending view, matching taskwarrior CLI
behavior. The waiting filter toggle now correctly shows only waiting tasks.
Fixes #592
Screenshots
Checklist
Summary by CodeRabbit
Release Notes
New Features
Chores